#include "messageshowarea.h"
#include <QIcon>
#include <QScrollBar>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QFont>
#include <QFontMetrics>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <QTextOption>
#include <QFileDialog>
#include <QMenu>
#include "debug.h"
#include "model/data.h"
#include "userinfowidget.h"
#include "mainWidget.h"
#include "model/datacenter.h"
#include "toast.h"
#include "model/data.h"
#include "soundrecorder.h"
using namespace model;


///////////////////////////////////////////////////////////////
/// 消息对话滚动区域的实现
///////////////////////////////////////////////////////////////
messageShowArea::messageShowArea()
{
    //1.初始化基本属性
    this->setWidgetResizable(true);
    this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    this->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal{height:0px;}");
    this->verticalScrollBar()->setStyleSheet("QScrollBar:vertical{width:3px;background-color:rgb(216,216,216);}");

    //2.设置container
    container = new QWidget;
    this->setWidget(container);

    //3.添加布局管理器
    QVBoxLayout* layout = new QVBoxLayout;
    container->setLayout(layout);

    //测试代码
#if TEST_UI
    for(int i =11;i<=30;i++)
    {
        UserInfo userInfo;
        userInfo.nickname = "zzy"+QString::number(i);
        userInfo.avatar=QIcon(":/myResource/Image/dogAvatar.svg");
        Message m = Message::makeMessage(MessageType::TEXT_TYPE,"",userInfo
                                         ,QString("这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息这是测试消息").toUtf8(),"");
        this->addMessage(true,m);
    }
    for(int i =10;i>=1;i--)
    {
        UserInfo userInfo;
        userInfo.nickname = "zzy"+QString::number(i);
        userInfo.avatar=QIcon(":/myResource/Image/dogAvatar.svg");
        Message m = Message::makeMessage(MessageType::TEXT_TYPE,"",userInfo
                                         ,QString("111111").toUtf8(),"");
        this->addFrontMessage(false,m);
    }


#endif

}
void messageShowArea::addMessage(bool isLeft,const Message& message)
{
    messageItem* item = new messageItem(isLeft,message);
    container->layout()->addWidget(item);

}
void messageShowArea::addFrontMessage(bool isLeft,const Message& message)
{
    messageItem* item = new messageItem(isLeft,message);
    dynamic_cast<QVBoxLayout*>(container->layout())->insertWidget(0,item);
}
void messageShowArea::clear()
{
    for(int i =this->container->layout()->count()-1;i>=0;i--)
    {
        QLayoutItem* item = this->container->layout()->takeAt(i);
        if(item&&item->widget())
        delete item->widget();
    }
}

//获取滚动条最大长度，并设置滚动条到最大长度
void messageShowArea::scrollToEnd()
{
    QTimer* timer = new QTimer;
    connect(timer,&QTimer::timeout,this,[=]()
    {
        int maxLength = this->verticalScrollBar()->maximum();
        this->verticalScrollBar()->setValue(maxLength);

        timer->stop();
        timer->deleteLater();
    });
    timer->start(500);
}




///////////////////////////////////////////////////////////////
/// 消息Item的实现
///////////////////////////////////////////////////////////////

messageItem::messageItem(bool isLeft,const Message& message)
{
    //1.创建网状布局管理器
    this->isLeft = isLeft;
    this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    QGridLayout* layout = new QGridLayout;
    layout->setContentsMargins(20/SCALE,0,10/SCALE,0);
    layout->setSpacing(10/SCALE);

    this->setMinimumHeight(100/SCALE);
    this->setLayout(layout);

    //2.设置发送信息用户头像

    QPushButton* userAvatar = new QPushButton;
    userAvatar->setIcon(message.sender.avatar);
    userAvatar->setFixedSize(45/SCALE,45/SCALE);
    userAvatar->setIconSize(QSize(45/SCALE,45/SCALE));
    userAvatar->setStyleSheet("QPushButton{border: none;}");
    if(isLeft)
        layout->addWidget(userAvatar,0,0,2,1,Qt::AlignTop);
    else
        layout->addWidget(userAvatar,0,1,2,1,Qt::AlignTop);
    //3.设置发送信息用户名字和发送消息时的时间
    QLabel* nameLabel =new QLabel;
    nameLabel->setText(message.sender.nickname+"|"+message.time);
    nameLabel->setAlignment(Qt::AlignBottom);
    nameLabel->setFixedHeight(15);
    nameLabel->setStyleSheet("QLabel{font-size:12px;color:rbg(178,178,178);}");
    if(isLeft)
        layout->addWidget(nameLabel,0,1,Qt::AlignLeft);
    else
        layout->addWidget(nameLabel,0,0,Qt::AlignRight);


    //4.创建并设置消息体
    QWidget* messageContentWidget = nullptr;
    switch(message.messageType)
    {
        case MessageType::TEXT_TYPE:
            messageContentWidget=new MessageContentLabel(message.content,message.messageType
                                ,isLeft,"",QByteArray());
            break;
        case MessageType::FILE_TYPE:
            messageContentWidget=new MessageContentLabel("[文件]"+message.fileName
                                ,message.messageType,isLeft,message.fileId,message.content);
            break;
        case MessageType::SPEECH_TYPE:
            messageContentWidget=new MessageContentLabel("[语音]"
                                ,message.messageType,isLeft,message.fileId,message.content);
            break;
        case MessageType::IMAGE_TYPE:
            messageContentWidget=new MessageImageLabel(isLeft,message.fileId,message.content);
            break;
        default:
            LOG()<<"错误的消息类型,MessageType:"<<(int)message.messageType;
    }

    if(isLeft){
        layout->addWidget(messageContentWidget,1,1);
    }
    else
        layout->addWidget(messageContentWidget,1,0);
    //初始化信号与槽
    model::DataCenter* dataCenter = model::DataCenter::getInstance();
    connect(userAvatar,&QPushButton::clicked,this,[this,message]()
    {
        MainWidget* mainWidget = MainWidget::getInstance();
        userInfoWidget* selfinfoWidget = new userInfoWidget(mainWidget,&message.sender);
        selfinfoWidget->exec();
    });
    if(!isLeft)
    {
        connect(dataCenter,&model::DataCenter::changeNicknameDone,this,[=]()
        {
            nameLabel->setText(dataCenter->getMyself()->nickname+"|"+message.time);
        });
        connect(dataCenter,&model::DataCenter::changeAvatarDone,this,[=]()
        {
            userAvatar->setIcon(dataCenter->getMyself()->avatar);
        });
    }

}


///////////////////////////////////////////////////////////////
/// 消息体的实现
///////////////////////////////////////////////////////////////


//文本消息，文件消息，语音消息的消息体(要和图片消息区分开的根本原因原因是微信的图片发送不需要手动画图)

MessageContentLabel::MessageContentLabel(const QString& text,model::MessageType messageType
                        ,bool isLeft,const QString& fileId,const QByteArray& content)
    :messageType(messageType),isLeft(isLeft),fileId(fileId),content(content)
{

    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    QFont font;
    font.setFamily("微软雅黑");
    //font.setFamily("Consolas");
    font.setPixelSize(14);

    this->label = new QLabel(this);
    //this->label->setTextInteractionFlags(Qt::TextSelectableByMouse);

    this->label->setText(text);
    this->label->setFont(font);
    this->label->setAlignment(Qt::AlignVCenter|Qt::AlignLeft);
    //这里有一个bug，就是对过长的一个单词分不了行，导致被截断
    this->label->setWordWrap(true);

    this->label->setContentsMargins(0,0,0,0);
    this->label->setStyleSheet("QLabel{padding:0 5px;line-height:1.2;background-color:transparent;}");

    if(messageType==model::MessageType::TEXT_TYPE) return;
    if(content.isEmpty())
    {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter,&model::DataCenter::getSingleFileDone,this,&MessageContentLabel::updateUI);
        dataCenter->getSingleFileAsync(fileId);
    }
    else
        isLoadContentDone = true;
}
void MessageContentLabel::paintEvent(QPaintEvent* event)
{
    (void)event;
    //1.获取父元素的宽度
    QObject* object = this->parent();
    if(!object->isWidgetType()){
        qDebug()<<"中途退出";
        return;
    }

    QWidget* parent = dynamic_cast<QWidget*>(object);
    int width = parent->width()*0.6;

    //2.计算应该分多少行
    QFontMetrics metrics(this->label->font());
    int totalWidth = 0,nCount =0,row = 0;//换行符个数
    //下面是以每个换行符为截断，计算每一行的row,并对每一行的row进行累加，并获取最大宽度
    for(auto& line:label->text().split('\n'))
    {
        int lineWidth = metrics.horizontalAdvance(line);
        totalWidth = qMax(totalWidth,lineWidth);
        //宽度需要左右留出10px,并向上取整
        row += (lineWidth-1)/(width-20)+1;
        nCount++;
    }
    row+=nCount-1;//增加换行符造成的影响
    //如果只有一行，宽度随着文本的长度而改变
    if(totalWidth+20<width) width = totalWidth+20;

    //3.计算需要画的高度
    int height =row*this->label->font().pixelSize()*1.2+20;
    //LOG()<<this->label->height()<<" "<<i++<<" "<<label->text();
    //4.画图
    QPainter painter(this);
    QPainterPath path;

    painter.setRenderHint(QPainter::Antialiasing);
    if(isLeft)
    {
        painter.setPen(QPen(QColor(255,255,255)));
        painter.setBrush(QColor(255,255,255));

        //绘制圆角矩形
        painter.drawRoundedRect(10,0,width,height,10,10);
        //绘制箭头
        path.moveTo(10,10);
        path.lineTo(0,15);
        path.lineTo(10,20);
        path.closeSubpath();
        painter.drawPath(path);

        this->label->setGeometry(10,0,width,height);
    }
    else
    {
        painter.setPen(QPen(QColor(137,217,97)));
        painter.setBrush(QColor(137,217,97));

        //绘制圆角矩形
        //计算出矩形的左右坐标
        int leftPos =this->width()-width-10;
        int rightPos = this->width()-10;

        painter.drawRoundedRect(leftPos,0,width,height,10,10);
        //绘制箭头
        path.moveTo(rightPos,10);
        path.lineTo(rightPos+10,15);
        path.lineTo(rightPos,20);
        path.closeSubpath();
        painter.drawPath(path);
        this->label->setGeometry(leftPos,0,width,height);
    }
    parent->setFixedHeight(height+40);

}

void MessageContentLabel::mousePressEvent(QMouseEvent *event)
{
    //触发左键按下后
    if(event->button()==Qt::LeftButton)
    {
        if(messageType==model::MessageType::FILE_TYPE)
        {
            if(isLoadContentDone==false)
            {
                Toast::showMessage("文件尚未加载完成，请稍后再试");
                return;
            }
            saveAsFile(this->content);
        }
        else if(messageType==model::MessageType::SPEECH_TYPE)
        {
            if(isLoadContentDone==false)
            {
                Toast::showMessage("语音尚未加载完成，请稍后再试");
                return;
            }
            playSpeech(this->content);
        }
    }
}

void MessageContentLabel::updateUI(const QString &fileId, const QByteArray &content)
{
    if(fileId!=this->fileId) return;
    this->content=content;
    this->isLoadContentDone = true;
    //由于文件消息或语音消息UI界面只会根据消息类型不同输出不
    //同的字体，因此仅仅获取到了内容是不需要使用update函数的
}

void MessageContentLabel::saveAsFile(const QByteArray &fileContent)
{
    QString filePath = QFileDialog::getSaveFileName(this,"另存为",QDir::homePath(),"*");
    if(filePath.isEmpty())
    {
        LOG()<<"用户取消了文件另存为";
        return;
    }
    writeByteArrayToFile(filePath,content);
}

void MessageContentLabel::playSpeech(const QByteArray &speechContent)
{
    label->setText("播放中...");
    SoundRecorder* soundRecorder =SoundRecorder::getInstance();
    connect(soundRecorder,&SoundRecorder::soundPlayDone,this,&MessageContentLabel::speechPlayDone,Qt::UniqueConnection);
    soundRecorder->startPlay(speechContent);
}

void MessageContentLabel::speechPlayDone()
{
    label->setText("[语音]");
}


void MessageContentLabel::contextMenuEvent(QContextMenuEvent *event)
{
    (void)event;
    if(messageType!=model::MessageType::SPEECH_TYPE) return;
    QMenu* menu = new QMenu(this);
    QAction* action = menu->addAction("语音转文字");
    //menu->setStyleSheet("QMenu{rgb{0,0,0};}");
    connect(action,&QAction::triggered,this,&MessageContentLabel::rightClicked);
    menu->exec(event->globalPos());
    delete menu;
}
void MessageContentLabel::rightClicked()
{
    model::DataCenter* dataCenter = model::DataCenter::getInstance();
    connect(dataCenter,&model::DataCenter::speechConvertTextDone,this,&MessageContentLabel::speechConvertText);
    dataCenter->speechConvertTextAsync(fileId,content);
}

void MessageContentLabel::speechConvertText(const QString &fileId, const QString &content)
{
    if(this->fileId!=fileId) return;
    this->label->setText(content);
    this->update();
}

//图片消息的消息体

MessageImageLabel::MessageImageLabel(bool isLeft,const QString& fileId,const QByteArray& content)
{
    this->isLeft=isLeft;
    this->fileId=fileId;
    this->content = content;
    imageBtn = new QPushButton(this);
    imageBtn->setStyleSheet("QPushButton{border:none;}");
    //没有消息内容，只有文件Id,代表这个消息不是用户直接本地发送的，而是从消息列表获取的
    if(content.isEmpty())
    {
        model::DataCenter* dataCenter = model::DataCenter::getInstance();
        connect(dataCenter,&model::DataCenter::getSingleFileDone,this,&MessageImageLabel::updateUI);
        dataCenter->getSingleFileAsync(fileId);
    }

}

void MessageImageLabel::updateUI(const QString& fileId,const QByteArray& content)
{
    //保证需要更新的对应图片消息是正确的
    if(fileId!=this->fileId)
        return;
    this->content = content;
    this->update();
}

void MessageImageLabel::paintEvent(QPaintEvent *event)
{
    (void)event;

    //1.获取父窗口
    QObject* object =this->parent();
    if(!object->isWidgetType()) return;
    QWidget* parent = dynamic_cast<QWidget*>(object);

    //2.读取照片
    //这里使用Image读取数据是因为Image读取数据能自动识别图片是什么类型
    QImage image;
    if(content.isEmpty())
        image.loadFromData(loadFileToByteArray(":/myResource/Image/defaultImage.svg"));
    else
        image.loadFromData(content);

    //3.计算图片长宽，同时防止图片太细
    double scale = qMin((double)image.width()/image.height(),(double)3);
    scale = qMax(scale,(double)1/3);
    imageBtn->setIcon(QIcon(QPixmap(QPixmap::fromImage(image))));
    //要求显示图片的面积是定值
    double basis = qSqrt(scale);
    int width =140*basis;
    int height = 140/basis;
    imageBtn->setIconSize(QSize(width,height));

    //4.设置父窗口长度
    parent->setFixedHeight(height+50);

    //5.确定按钮所在位置
    if(isLeft)
        imageBtn->setGeometry(10,0,width,height);
    else
        imageBtn->setGeometry(this->width()-10-width,0,width,height);

}


